<?php
/*
 * $Id: StringTest.class.php 156 2009-12-16 15:59:00Z namba0219 $
 * =============================================================================
 * Barge - web application framework on PHP5
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For more information, see http://barge.googlecode.com/
 */
namespace barge\utils;

use \Exception;
use \UnitTestCase;

use barge\System;
use barge\utils\ArrayList;
use barge\utils\HashMap;
use barge\utils\String;
use barge\utils\IndexOutOfBoundsException;
use barge\utils\IllegalAccessException;
use barge\utils\IllegalArgumentException;

/**
 * @see UnitTestCase
 */
class StringTest extends UnitTestCase
{

	/**
	 * @test
	 */
	public function testCompare()
	{
		$this->assertTrue(String::compare(1, 2) < 0);
		$this->assertTrue(String::compare(1, 1) === 0);
		$this->assertTrue(String::compare(2, 1) > 0);
		$this->assertTrue(String::compare("1", "2") < 0);
		$this->assertTrue(String::compare("1", "1") === 0);
		$this->assertTrue(String::compare("2", "1") > 0);
		$this->assertTrue(String::compare("2", "10") > 0);
	}

	/**
	 * @test
	 */
	public function testConcat()
	{
		$this->assertIdentical(String::concat("1", "2"), "12");
		$this->assertIdentical(String::concat("1", null), "1");
		$this->assertIdentical(String::concat("01", "2"), "012");
	}

	/**
	 * @test
	 */
	public function testDefaultIfEmpty()
	{
		$this->assertIdentical(String::defaultIfEmpty(null), '');
		$this->assertIdentical(String::defaultIfEmpty(''), '');
		$this->assertIdentical(String::defaultIfEmpty('', 'a'), 'a');
		$this->assertIdentical(String::defaultIfEmpty('b'), 'b');
		$this->assertIdentical(String::defaultIfEmpty(' '), ' ');
	}

	/**
	 * @test
	 */
	public function testDefaultString()
	{
		$this->assertIdentical(String::defaultString(null), '');
		$this->assertIdentical(String::defaultString(null, 'a'), 'a');
		$this->assertIdentical(String::defaultString('', 'a'), '');
		$this->assertIdentical(String::defaultString(' '), ' ');
		$this->assertIdentical(String::defaultString('abc'), 'abc');
	}

	/**
	 * @test
	 */
	public function testEndsWith()
	{
		$this->assertTrue(String::endsWith('abc', 'c'));
		$this->assertTrue(String::endsWith('abc', 'bc'));
		$this->assertTrue(String::endsWith('abc', 'abc'));
		$this->assertTrue(String::endsWith('あいうえお', 'お'));
		$this->assertTrue(String::endsWith('ダイアリー', 'ー'));
		$this->assertTrue(String::endsWith('abc', 'a') === false);
		$this->assertTrue(String::endsWith('abc', null) === false);
	}

	/**
	 * @test
	 */
	public function testCharAt()
	{
		$this->assertIdentical(String::charAt('abc', 0), 'a');
		$this->assertIdentical(String::charAt('abc', 1), 'b');
		$this->assertIdentical(String::charAt('abc', 2), 'c');
		try {
			String::charAt('abc', 3);
			$this->fail();
		} catch (Exception $e) {}
	}

	/**
	 * @test
	 */
	public function testDefaultCharAt()
	{
		$this->assertIdentical(String::defaultCharAt('abc', 0, 'z'), 'a');
		$this->assertIdentical(String::defaultCharAt('abc', 1, 'z'), 'b');
		$this->assertIdentical(String::defaultCharAt('abc', 2, 'z'), 'c');
		$this->assertIdentical(String::defaultCharAt('abc', 3, 'z'), 'z');
	}

	/**
	 * @test
	 */
	public function testFormat()
	{
		$this->assertIdentical(String::format(null), null);
		$this->assertIdentical(String::format('abc'), 'abc');
		$this->assertIdentical(String::format('abc={0}', 1), 'abc=1');
		$this->assertIdentical(String::format('abc={0}=def', 1), 'abc=1=def');
		$this->assertIdentical(String::format('abc={0}{1}', 1, 2), 'abc=12');
		$this->assertIdentical(String::format('abc={0}{1}', array('a', 'b')), 'abc=ab');
		$this->assertIdentical(String::format('abc={0}{0}', array('a', 'b')), 'abc=aa');
		$this->assertIdentical(String::format('abc={0}{2}', 1), 'abc=1');
		$this->assertIdentical(String::format('abc={key1}{key2}', array('key1'=>'a', 'key2'=>'b')), 'abc=ab');
		$this->assertIdentical(String::format('abc={0|substr:0:1}', 'abcdefg'), 'abc=a');
		$this->assertIdentical(String::format('{0|substr:1}', 'abcdefg'), 'bcdefg');
		$this->assertIdentical(String::format('{0|camelize}', 'action_key'), 'ActionKey');
		$this->assertIdentical(String::format('{0|camelize:1}', 'action_key'), 'actionKey');
		$this->assertIdentical(String::format('{0|substr:1|capitalize}', 'abcdefg'), 'Bcdefg');
		$this->assertIdentical(String::format("{0|replace:'a':'_'}", 'abcdafga'), '_bcd_fg_');
//		$this->assertTrue(String::format('{0|substr:1|str_pad:10}', 'abcdefg') === 'bcdefg    ');
		try {
			String::format('abc={0|unknown}', 'abcdefg');;
			$this->fail();
		} catch (IllegalArgumentException $e){}
	}

	/**
	 * @test
	 */
	public function testIndexOf()
	{
		$this->assertIdentical(String::indexOf(null, 'abc'), -1);
		$this->assertIdentical(String::indexOf('abc', 'd'), -1);
		$this->assertIdentical(String::indexOf('abcdef', 'abc'), 0);
		$this->assertIdentical(String::indexOf('abcdef', 'bc'), 1);
		$this->assertIdentical(String::indexOf('abcdef', 'bc', 1), 1);
		$this->assertIdentical(String::indexOf('abcdefabcdef', 'ab', 1), 6);
		$this->assertIdentical(String::indexOf('abcdefgabcdefg', 'a'), 0);
		$this->assertIdentical(String::indexOf('１２３４５６７８９０', '２'), 1);
	}

	/**
	 * @test
	 */
	public function testIsBlank()
	{
		$this->assertIdentical(String::isBlank(''), true);
		$this->assertIdentical(String::isBlank(' '), true);
		$this->assertIdentical(String::isBlank(null), true);
		$this->assertIdentical(String::isBlank('a'), false);
		$this->assertIdentical(String::isBlank('abc'), false);
		$this->assertIdentical(String::isBlank(1), false);
	}

	/**
	 * @test
	 */
	public function testIsEmpty()
	{
		$this->assertIdentical(String::isEmpty(''), true);
		$this->assertIdentical(String::isEmpty(' '), false);
		$this->assertIdentical(String::isEmpty(null), true);
		$this->assertIdentical(String::isEmpty('a'), false);
		$this->assertIdentical(String::isEmpty('abc'), false);
		$this->assertIdentical(String::isEmpty(1), false);
	}

	/**
	 * @test
	 */
	public function testIsNotBlank()
	{
		$this->assertIdentical(String::isNotBlank(''), false);
		$this->assertIdentical(String::isNotBlank(' '), false);
		$this->assertIdentical(String::isNotBlank(null), false);
		$this->assertIdentical(String::isNotBlank('a'), true);
		$this->assertIdentical(String::isNotBlank('abc'), true);
		$this->assertIdentical(String::isNotBlank(1), true);
	}

	/**
	 * @test
	 */
	public function testIsNotEmpty()
	{
		$this->assertIdentical(String::isNotEmpty(''), false);
		$this->assertIdentical(String::isNotEmpty(' '), true);
		$this->assertIdentical(String::isNotEmpty(null), false);
		$this->assertIdentical(String::isNotEmpty('a'), true);
		$this->assertIdentical(String::isNotEmpty('abc'), true);
		$this->assertIdentical(String::isNotEmpty(1), true);
	}

	/**
	 * @test
	 */
	public function testLastIndexOf()
	{
		$this->assertIdentical(String::lastIndexOf('abcdefg', 'a'), 0);
		$this->assertIdentical(String::lastIndexOf('abcdefg', 'abcdefg'), 0);
		$this->assertIdentical(String::lastIndexOf('abcdefg', 'bcd'), 1);
		$this->assertIdentical(String::lastIndexOf('abcdefg', '1'), -1);
		$this->assertIdentical(String::lastIndexOf('abcdefg', 'bcd', 1), 1);
		$this->assertIdentical(String::lastIndexOf('abcdefg', 'bcd', 2), -1);
		$this->assertIdentical(String::lastIndexOf('abcdefgabcdefg', 'a'), 7);
		$this->assertIdentical(String::lastIndexOf('abcdefgabcdefg', 'g', -2), 6);
	}

	/**
	 * @test
	 */
	public function testLeftPad()
	{
		$this->assertIdentical(String::leftPad('abcdefg', 10), '   abcdefg');
		$this->assertIdentical(String::leftPad('abcdefg', 10, '_'), '___abcdefg');
		$this->assertIdentical(String::leftPad('abcdefg', 7), 'abcdefg');
		$this->assertIdentical(String::leftPad('abcdefg', 6), 'abcdefg');
		$this->assertIdentical(String::leftPad('abcdefg', 0), 'abcdefg');
		$this->assertIdentical(String::leftPad('１２３４５６７８９', 20), '           １２３４５６７８９');
		$this->assertIdentical(String::leftPad('１２３４５６７８９', 10), ' １２３４５６７８９');
		try {
			String::leftPad('abc', 10, null);
			$this->fail();
		} catch (IllegalArgumentException $e){}
			try {
			String::leftPad('abc', 10, '');
			$this->fail();
		} catch (IllegalArgumentException $e){}
		// FIXME :
//		$this->assertTrue(String::leftPad('abcdefg', 10, '12') === '12abcdefg');
	}

	/**
	 * @test
	 */
	public function testLowerCase()
	{
		$this->assertIdentical(String::lowerCase(null), null);
		$this->assertIdentical(String::lowerCase(''), '');
		$this->assertIdentical(String::lowerCase('abcdefg'), 'abcdefg');
		$this->assertIdentical(String::lowerCase('ABCDEFGHIJKLMNOPQRSTUVWSYZ'), 'abcdefghijklmnopqrstuvwsyz');
	}

	/**
	 * @test
	 */
	public function testMatch()
	{
		$this->assertIdentical(String::match(null, '/\w+/'), false);
		$this->assertIdentical(String::match('', '/\w+/'), false);
		$this->assertIdentical(String::match('abc', '/\w+/'), true);
		$this->assertIdentical(String::match('1234567890', '/\w+/'), true);
	}

	/**
	 * @test
	 */
	public function testReplace()
	{
		$this->assertIdentical(String::replace(null, '1', 'a'), null);
		$this->assertIdentical(String::replace('', '1', 'a'), '');
		$this->assertIdentical(String::replace('abc', 'a', 'A'), 'Abc');
		$this->assertIdentical(String::replace('abcabc', 'abc', 'ABC'), 'ABCABC');
	}

	/**
	 * @test
	 */
	public function testRightPad()
	{
		$this->assertTrue(String::rightPad('abcdefg', 10) === 'abcdefg   ');
		$this->assertTrue(String::rightPad('abcdefg', 10, '_') === 'abcdefg___');
		$this->assertTrue(String::rightPad('abcdefg', 7) === 'abcdefg');
		$this->assertTrue(String::rightPad('abcdefg', 6) === 'abcdefg');
		$this->assertTrue(String::rightPad('abcdefg', 0) === 'abcdefg');
		$this->assertTrue(String::rightPad('１２３４５６７８９', 20) === '１２３４５６７８９           ');
		$this->assertTrue(String::rightPad('１２３４５６７８９', 10) === '１２３４５６７８９ ');
		try {
			String::rightPad('abc', 10, null);
			$this->fail();
		} catch (IllegalArgumentException $e){}
			try {
			String::rightPad('abc', 10, '');
			$this->fail();
		} catch (IllegalArgumentException $e){}
	}

	/**
	 * @test
	 */
	public function testSplit()
	{
		$this->assertIdentical(String::split(null, ',')->size(), 0);
		$this->assertIdentical(String::split('', ',')->size(), 1);
		$this->assertTrue(String::split('5,10,11', ',') instanceof ArrayList);
		$this->assertIdentical(String::split('5,10,11', ',')->size(), 3);
		$this->assertIdentical(String::split('5,10,11,', ',')->size(), 4);
		$this->assertIdentical(String::split(',5,10,11', ',')->size(), 4);
	}

	/**
	 * @test
	 */
	public function testSprintf()
	{
		$this->assertIdentical(String::sprintf(null), null);
		$this->assertIdentical(String::sprintf(''), '');
		$this->assertIdentical(String::sprintf('%s=%d', 'name', 1), 'name=1');
		$this->assertIdentical(String::sprintf('%s=%d', array('name', 1)), 'name=1');
	}

	/**
	 * @test
	 */
	public function testStartsWith()
	{
		$this->assertIdentical(String::startsWith(null, null), false);
		$this->assertIdentical(String::startsWith('', ''), false);
		$this->assertIdentical(String::startsWith('abc', 'a'), true);
		$this->assertIdentical(String::startsWith('abc', 'ab'), true);
		$this->assertIdentical(String::startsWith('abc', 'abc'), true);
		$this->assertIdentical(String::startsWith('123', '1'), true);
		$this->assertIdentical(String::startsWith('123', 1), true);
		$this->assertIdentical(String::startsWith('インプット', 'イン'), true);
	}

	/**
	 * @test
	 */
	public function testSubstr()
	{
		$this->assertIdentical(String::substr(null, 0, 1), null);
		$this->assertIdentical(String::substr('', 0, 1), '');
		$this->assertIdentical(String::substr('abc', 1), 'bc');
		$this->assertIdentical(String::substr('abc', 1, 1), 'b');
		$this->assertIdentical(String::substr('abc', 1, 100), 'bc');
		$this->assertIdentical(String::substr('abcdefg', 1, -1), 'bcdef');
		$this->assertIdentical(String::substr('abcdefg', 1, -100), '');
		$this->assertIdentical(String::substr('abcdefg', 100), '');
		$this->assertIdentical(String::substr('abcdefg', -1, 1), 'g');
		$this->assertIdentical(String::substr('１２３４５６', 0, 1), '１');
		$this->assertIdentical(String::substr('１２３４５６', 1, 1), '２');
		$this->assertIdentical(String::substr('１２３４５６', 1, -1), '２３４５');
	}

	/**
	 * @test
	 */
	public function testSubstring()
	{
		$this->assertIdentical(String::substring(null, 0, 1), null);
		$this->assertIdentical(String::substring('', 0, 1), '');
		$this->assertIdentical(String::substring('abc', 1), 'bc');
		$this->assertIdentical(String::substring('abc', 1, 2), 'b');
		$this->assertIdentical(String::substring('abc', 1, 100), 'bc');
		$this->assertIdentical(String::substring('abcdefg', 100), '');
		try {
			String::substring('abcdefg', 1, -10);
			$this->fail();
		} catch (IllegalArgumentException $e){}
	}

	/**
	 * @test
	 */
	public function testUpperCase()
	{
		$this->assertIdentical(String::upperCase(null), null);
		$this->assertIdentical(String::upperCase(''), '');
		$this->assertIdentical(String::upperCase('abcdefghijklmnopqrstuvwsyz'), 'ABCDEFGHIJKLMNOPQRSTUVWSYZ');
		$this->assertIdentical(String::upperCase('ABCDEFGHIJKLMNOPQRSTUVWSYZ'), 'ABCDEFGHIJKLMNOPQRSTUVWSYZ');
	}

	/**
	 * @test
	 */
	public function testTrim()
	{
		$this->assertIdentical(String::trim(null), null);
		$this->assertIdentical(String::trim(''), '');
		$this->assertIdentical(String::trim(' abc '), 'abc');
		$this->assertIdentical(String::trim(' abc'), 'abc');
		$this->assertIdentical(String::trim('abc '), 'abc');
		$this->assertIdentical(String::trim('$abc$', '$'), 'abc');
	}

	/**
	 * @test
	 */
	public function testLength()
	{
		$this->assertIdentical(String::length(null), 0);
		$this->assertIdentical(String::length(''), 0);
		$this->assertIdentical(String::length('abc'), 3);
		$this->assertIdentical(String::length('あああ'), 3);
		$this->assertIdentical(String::length('‘’'), 2);
	}

	/**
	 * @test
	 */
	public function testWidth()
	{
		System::setProperty('System/language', 'ja_JP');
		$this->assertIdentical(String::width(null), 0);
		$this->assertIdentical(String::width(''), 0);
		$this->assertIdentical(String::width('abc'), 3);
		$this->assertIdentical(String::width('あいう'), 6);
		$this->assertIdentical(String::width('ｱｲｳ'), 3);
		$this->assertIdentical(String::width('＠'), 2);
		$this->assertIdentical(String::width('｢｣ﾞﾟ'), 4);
		$this->assertIdentical(String::width('｢｣'), 2);
		$this->assertIdentical(String::width('⑩'), 2);	// mb_strwidth:1
		$this->assertIdentical(String::width('ω'), 2);	// mb_strwidth:1
		$this->assertIdentical(String::width('※'), 2);	// mb_strwidth:1

	}

	/**
	 * @test
	 */
	public function testQuote()
	{
		$this->assertIdentical(String::quote(null), "''");
		$this->assertIdentical(String::quote('a'), "'a'");
		$this->assertIdentical(String::quote('abc', '"'), '"abc"');
		$this->assertIdentical(String::quote('"a', '"', String::ESCAPE_NONE), '""a"');
		$this->assertIdentical(String::quote('"a', '"', String::ESCAPE_REPEAT), '"""a"');
		$this->assertIdentical(String::quote('"a', '"', String::ESCAPE_YEN), '"\\"a"');

		// TOOD :
	}

}
